--! This file is part of the Wupper firmware distribution (https://gitlab.nikhef.nl/franss/wupper).
--! Copyright (C) 2001-2021 CERN for the benefit of the ATLAS collaboration.
--! Authors:
--!               Mark Donszelmann
--!               Andrea Borga
--!               Soo Ryu
--!               Kai Chen
--!               Israel Grayzman
--!               Rene Habraken
--!               Alexander Paramonov
--!               RHabraken
--!               Nayib Boukadida
--!               Alessandra Camplani
--!               Elena Zhivun
--!               Mesfin Gebyehu
--!               Rene
--!               Thei Wijnen
--!               Ohad Shaked
--!               Alessandro Thea
--!               mtrovato
--!               Frans Schreuder
--! 
--!   Licensed under the Apache License, Version 2.0 (the "License");
--!   you may not use this file except in compliance with the License.
--!   You may obtain a copy of the License at
--!
--!       http://www.apache.org/licenses/LICENSE-2.0
--!
--!   Unless required by applicable law or agreed to in writing, software
--!   distributed under the License is distributed on an "AS IS" BASIS,
--!   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--!   See the License for the specific language governing permissions and
--!   limitations under the License.
-- ***************************************************************************
-- ***************************************************************************
-- ***************************************************************************
-- ***************************************************************************
-- ***************************************************************************
-- DO NOT EDIT THIS FILE
-- 
-- This file was generated from template '../firmware/sources/templates/pcie_package.vhd.template'
-- and register map registers-2.0.yaml, version 2.0
-- by the script 'wuppercodegen', version: 0.9.1,
-- using the following commandline:
-- 
-- ../software/wuppercodegen/wuppercodegen/cli.py registers-2.0.yaml ../firmware/sources/templates/pcie_package.vhd.template ../firmware/sources/pcie/pcie_package.vhd
-- 
-- Please do NOT edit this file, but edit the source file at '../firmware/sources/templates/pcie_package.vhd.template'
-- 
-- ***************************************************************************
-- ***************************************************************************
-- ***************************************************************************
-- ***************************************************************************
-- ***************************************************************************


--!------------------------------------------------------------------------------
--!
--!           NIKHEF - National Institute for Subatomic Physics
--!
--!                       Electronics Department
--!
--!-----------------------------------------------------------------------------
--! @class pcie_package
--!
--!
--! @author      Andrea Borga    (andrea.borga@nikhef.nl)<br>
--!              Frans Schreuder (frans.schreuder@nikhef.nl)
--!
--!
--! @date        07/01/2015    created
--!
--! @version     1.0
--!
--! @brief
--! This package contains the data types for the PCIe DMA core, as well as some
--! constants, addresses and register types for the application.
--!
--!
--! @detail
--!
--!-----------------------------------------------------------------------------
--! @TODO
--!
--!
--! ------------------------------------------------------------------------------
--!

--! @brief ieee



library ieee;
use ieee.numeric_std.all;
--use ieee.std_logic_unsigned.all;
use ieee.std_logic_1164.all;

package pcie_package is

  function to_sl( A: std_logic_vector) return std_logic ;
  function or_reduce(slv : in std_logic_vector) return std_logic ;
  --To go from nenory depth to number of address bits
  function f_log2 (constant x : positive) return natural;
  --! If we have multiple descriptors ToHost (take one off for FromHost direction) we have more FIFOs, let's make them less deep.
  function TOHOSTFIFO_DEPTH(NUMBER_OF_DESCRIPTORS : integer; FIRMWARE_MODE: integer) return integer;
  --
  -- PCIe DMA core: AXI-4 Stream interface
  type axis_type is record
    tdata   : std_logic_vector(1023 downto 0);
    tkeep   : std_logic_vector(31 downto 0);
    tuser   : std_logic_vector(464 downto 0);
    tlast   : std_logic;
    tvalid  : std_logic;
    --state   : std_logic_vector(2 downto 0); --debugging purposes, connected to ILA
  end record;

  type axis_r_type is record
    tready: std_logic;
  end record;

  --
  -- PCIe DMA core: descriptors
  type dma_descriptor_type is record
    start_address   : std_logic_vector(63 downto 0);
    end_address     : std_logic_vector(63 downto 0);
    dword_count     : std_logic_vector(10 downto 0);
    read_not_write  : std_logic;     --1 means this is a read descriptor, 0: write descriptor
    enable          : std_logic;     --descriptor is valid
    wrap_around     : std_logic;     --1 means when end is reached, keep enabled and start over
    evencycle_pc    : std_logic;     --For every time the pc pointer overflows, this bit toggles.
    pc_pointer      : std_logic_vector(63 downto 0); --Last address that the PC has read / written. For write: overflow and read until this cycle.
    pc_pointer_updated : std_logic;  --Pulse when the pc_pointer is written
  end record;

  type dma_descriptors_type is array (natural range <>) of dma_descriptor_type;

  type dma_status_type is record
    current_address : std_logic_vector(63 downto 0);
    evencycle_dma   : std_logic;     --For every time the current_address overflows, this bit toggles
    address_wrapped : std_logic;
  end record;

  type dma_statuses_type is array(natural range <>) of dma_status_type;

  --
  -- PCIe DMA core: Interrupt Vectors
  type interrupt_vector_type is record
    int_vec_add  : std_logic_vector(63 downto 0);
    int_vec_data : std_logic_vector(31 downto 0);
    int_vec_ctrl : std_logic_vector(31 downto 0);
  end record;

  type interrupt_vectors_type is array (natural range <>) of interrupt_vector_type;
  
  type slv_array is array (natural range <>) of std_logic_vector(1023 downto 0);
  type slv12_array is array (natural range <>) of std_logic_vector(11 downto 0);
  
  --For 2 Versal enpoints in CPM mode, we have to instantiate a single CIPS system. We use the following record to transfer the signals between CPM and Wupper
  type CPMToWupper_type is record
    PCIE_tx_n                   : std_logic_vector(7 downto 0);
    PCIE_tx_p                   : std_logic_vector(7 downto 0);
    cfg_interrupt_0_sent          : STD_LOGIC;
    cfg_msix_0_enable             : STD_LOGIC_VECTOR ( 3 downto 0 );
    --cfg_msix_0_fail               : STD_LOGIC;
    cfg_msix_0_mask               : STD_LOGIC_VECTOR ( 3 downto 0 );
    --cfg_msix_0_sent               : STD_LOGIC;
    --cfg_msix_0_vec_pending_status : STD_LOGIC;
    m_axis_cq_0_tdata             : STD_LOGIC_VECTOR ( 1023 downto 0 );
    m_axis_cq_0_tkeep             : STD_LOGIC_VECTOR ( 31 downto 0 );
    m_axis_cq_0_tlast             : STD_LOGIC;
    m_axis_cq_0_tuser             : STD_LOGIC_VECTOR ( 464 downto 0 );
    m_axis_cq_0_tvalid            : STD_LOGIC;
    m_axis_rc_0_tdata             : STD_LOGIC_VECTOR ( 1023 downto 0 );
    m_axis_rc_0_tkeep             : STD_LOGIC_VECTOR ( 31 downto 0 );
    m_axis_rc_0_tlast             : STD_LOGIC;
    m_axis_rc_0_tuser             : STD_LOGIC_VECTOR ( 336 downto 0 );
    m_axis_rc_0_tvalid            : STD_LOGIC;
    s_axis_cc_0_tready            : STD_LOGIC;
    s_axis_rq_0_tready            : STD_LOGIC;
    user_clk_0                    : STD_LOGIC;
    user_lnk_up_0                 : STD_LOGIC;
    user_reset_0                  : STD_LOGIC;
  end record;
  
  type CPMToWupper_array_type is array (natural range <>) of CPMToWupper_type;
  
  type WupperToCPM_type is record
    PCIE_rx_n                   : std_logic_vector(7 downto 0);
    PCIE_rx_p                   : std_logic_vector(7 downto 0);
    gtrefclk_n                  : std_logic;
    gtrefclk_p                  : std_logic;
    cfg_interrupt_0_intx_vector : STD_LOGIC_VECTOR ( 3 downto 0 );
    cfg_interrupt_0_pending     : STD_LOGIC_VECTOR ( 15 downto 0 );
    cfg_msix_0_address          : STD_LOGIC_VECTOR ( 63 downto 0 );
    cfg_msix_0_data             : STD_LOGIC_VECTOR ( 31 downto 0 );
    cfg_msix_0_function_number  : STD_LOGIC_VECTOR ( 15 downto 0 );
    cfg_msix_0_int_vector       : STD_LOGIC;
    cfg_msix_0_mint_vector      : STD_LOGIC_VECTOR ( 31 downto 0 );
    cfg_msix_0_vec_pending      : STD_LOGIC_VECTOR ( 1 downto 0 );
    m_axis_cq_0_tready          : STD_LOGIC;
    m_axis_rc_0_tready          : STD_LOGIC;
    s_axis_cc_0_tdata           : STD_LOGIC_VECTOR ( 1023 downto 0 );
    s_axis_cc_0_tkeep           : STD_LOGIC_VECTOR ( 31 downto 0 );
    s_axis_cc_0_tlast           : STD_LOGIC;
    s_axis_cc_0_tuser           : STD_LOGIC_VECTOR ( 164 downto 0 );
    s_axis_cc_0_tvalid          : STD_LOGIC;
    s_axis_rq_0_tdata           : STD_LOGIC_VECTOR ( 1023 downto 0 );
    s_axis_rq_0_tkeep           : STD_LOGIC_VECTOR ( 31 downto 0 );
    s_axis_rq_0_tlast           : STD_LOGIC;
    s_axis_rq_0_tuser           : STD_LOGIC_VECTOR ( 372 downto 0 );
    s_axis_rq_0_tvalid          : STD_LOGIC;
  end record;
  
  type WupperToCPM_array_type is array (natural range <>) of WupperToCPM_type;
    
  --! Address Offset assignment
  --! --> BAR0 User Application Registers Addresses
  -- ### BAR0 registers: start
  constant REG_DESCRIPTOR_0        : std_logic_vector(19 downto 0) := x"00000";
  constant REG_DESCRIPTOR_0a       : std_logic_vector(19 downto 0) := x"00010";
  constant REG_DESCRIPTOR_1        : std_logic_vector(19 downto 0) := x"00020";
  constant REG_DESCRIPTOR_1a       : std_logic_vector(19 downto 0) := x"00030";
  constant REG_DESCRIPTOR_2        : std_logic_vector(19 downto 0) := x"00040";
  constant REG_DESCRIPTOR_2a       : std_logic_vector(19 downto 0) := x"00050";
  constant REG_DESCRIPTOR_3        : std_logic_vector(19 downto 0) := x"00060";
  constant REG_DESCRIPTOR_3a       : std_logic_vector(19 downto 0) := x"00070";
  constant REG_DESCRIPTOR_4        : std_logic_vector(19 downto 0) := x"00080";
  constant REG_DESCRIPTOR_4a       : std_logic_vector(19 downto 0) := x"00090";
  constant REG_DESCRIPTOR_5        : std_logic_vector(19 downto 0) := x"000A0";
  constant REG_DESCRIPTOR_5a       : std_logic_vector(19 downto 0) := x"000B0";
  constant REG_DESCRIPTOR_6        : std_logic_vector(19 downto 0) := x"000C0";
  constant REG_DESCRIPTOR_6a       : std_logic_vector(19 downto 0) := x"000D0";
  constant REG_DESCRIPTOR_7        : std_logic_vector(19 downto 0) := x"000E0";
  constant REG_DESCRIPTOR_7a       : std_logic_vector(19 downto 0) := x"000F0";
  constant REG_DESCRIPTOR_8        : std_logic_vector(19 downto 0) := x"00100";
  constant REG_DESCRIPTOR_8a       : std_logic_vector(19 downto 0) := x"00110";
  constant REG_DESCRIPTOR_9        : std_logic_vector(19 downto 0) := x"00120";
  constant REG_DESCRIPTOR_9a       : std_logic_vector(19 downto 0) := x"00130";
  constant REG_DESCRIPTOR_10       : std_logic_vector(19 downto 0) := x"00140";
  constant REG_DESCRIPTOR_10a      : std_logic_vector(19 downto 0) := x"00150";
  constant REG_DESCRIPTOR_11       : std_logic_vector(19 downto 0) := x"00160";
  constant REG_DESCRIPTOR_11a      : std_logic_vector(19 downto 0) := x"00170";
  constant REG_DESCRIPTOR_12       : std_logic_vector(19 downto 0) := x"00180";
  constant REG_DESCRIPTOR_12a      : std_logic_vector(19 downto 0) := x"00190";
  constant REG_DESCRIPTOR_13       : std_logic_vector(19 downto 0) := x"001A0";
  constant REG_DESCRIPTOR_13a      : std_logic_vector(19 downto 0) := x"001B0";
  constant REG_DESCRIPTOR_14       : std_logic_vector(19 downto 0) := x"001C0";
  constant REG_DESCRIPTOR_14a      : std_logic_vector(19 downto 0) := x"001D0";
  constant REG_DESCRIPTOR_15       : std_logic_vector(19 downto 0) := x"001E0";
  constant REG_DESCRIPTOR_15a      : std_logic_vector(19 downto 0) := x"001F0";
  constant REG_STATUS_0            : std_logic_vector(19 downto 0) := x"00200";
  constant REG_STATUS_1            : std_logic_vector(19 downto 0) := x"00210";
  constant REG_STATUS_2            : std_logic_vector(19 downto 0) := x"00220";
  constant REG_STATUS_3            : std_logic_vector(19 downto 0) := x"00230";
  constant REG_STATUS_4            : std_logic_vector(19 downto 0) := x"00240";
  constant REG_STATUS_5            : std_logic_vector(19 downto 0) := x"00250";
  constant REG_STATUS_6            : std_logic_vector(19 downto 0) := x"00260";
  constant REG_STATUS_7            : std_logic_vector(19 downto 0) := x"00270";
  constant REG_STATUS_8            : std_logic_vector(19 downto 0) := x"00280";
  constant REG_STATUS_9            : std_logic_vector(19 downto 0) := x"00290";
  constant REG_STATUS_10           : std_logic_vector(19 downto 0) := x"002A0";
  constant REG_STATUS_11           : std_logic_vector(19 downto 0) := x"002B0";
  constant REG_STATUS_12           : std_logic_vector(19 downto 0) := x"002C0";
  constant REG_STATUS_13           : std_logic_vector(19 downto 0) := x"002D0";
  constant REG_STATUS_14           : std_logic_vector(19 downto 0) := x"002E0";
  constant REG_STATUS_15           : std_logic_vector(19 downto 0) := x"002F0";
  constant REG_BAR0                : std_logic_vector(19 downto 0) := x"00300";
  constant REG_BAR1                : std_logic_vector(19 downto 0) := x"00310";
  constant REG_BAR2                : std_logic_vector(19 downto 0) := x"00320";
  constant REG_DESCRIPTOR_ENABLE   : std_logic_vector(19 downto 0) := x"00400";
  constant REG_FIFO_FLUSH          : std_logic_vector(19 downto 0) := x"00410";
  constant REG_DMA_RESET           : std_logic_vector(19 downto 0) := x"00420";
  constant REG_SOFT_RESET          : std_logic_vector(19 downto 0) := x"00430";
  constant REG_REGISTER_RESET      : std_logic_vector(19 downto 0) := x"00440";
  constant REG_FROMHOST_FULL_THRESH: std_logic_vector(19 downto 0) := x"00450";
  constant REG_TOHOST_FULL_THRESH  : std_logic_vector(19 downto 0) := x"00460";
  constant REG_BUSY_THRESH_ASSERT  : std_logic_vector(19 downto 0) := x"00470";
  constant REG_BUSY_THRESH_NEGATE  : std_logic_vector(19 downto 0) := x"00480";
  constant REG_BUSY_STATUS         : std_logic_vector(19 downto 0) := x"00490";
  constant REG_PC_PTR_GAP          : std_logic_vector(19 downto 0) := x"004A0";
  constant REG_TOHOSTFIFO_EMPTY    : std_logic_vector(19 downto 0) := x"004B0";
  constant REG_TOHOSTFIFO_PEMPTY   : std_logic_vector(19 downto 0) := x"004C0";
  constant REG_FROMHOSTFIFO_FULL   : std_logic_vector(19 downto 0) := x"004D0";
  constant REG_FROMHOSTFIFO_PFULL  : std_logic_vector(19 downto 0) := x"004E0";
  
  -- BAR0 registers: end

  --! Address Offset assignment
  --! --> BAR1 User Application Registers Addresses
  -- ### BAR1 registers: start
     -- interrupt vectors
  constant REG_INT_VEC_00          : std_logic_vector(19 downto 0) := x"00000";
  constant REG_INT_VEC_01          : std_logic_vector(19 downto 0) := x"00010";
  constant REG_INT_VEC_02          : std_logic_vector(19 downto 0) := x"00020";
  constant REG_INT_VEC_03          : std_logic_vector(19 downto 0) := x"00030";
  constant REG_INT_VEC_04          : std_logic_vector(19 downto 0) := x"00040";
  constant REG_INT_VEC_05          : std_logic_vector(19 downto 0) := x"00050";
  constant REG_INT_VEC_06          : std_logic_vector(19 downto 0) := x"00060";
  constant REG_INT_VEC_07          : std_logic_vector(19 downto 0) := x"00070";
  constant REG_INT_VEC_08          : std_logic_vector(19 downto 0) := x"00080";
  constant REG_INT_VEC_09          : std_logic_vector(19 downto 0) := x"00090";
  constant REG_INT_VEC_10          : std_logic_vector(19 downto 0) := x"000A0";
  constant REG_INT_VEC_11          : std_logic_vector(19 downto 0) := x"000B0";
  constant REG_INT_VEC_12          : std_logic_vector(19 downto 0) := x"000C0";
  constant REG_INT_VEC_13          : std_logic_vector(19 downto 0) := x"000D0";
  constant REG_INT_VEC_14          : std_logic_vector(19 downto 0) := x"000E0";
  constant REG_INT_VEC_15          : std_logic_vector(19 downto 0) := x"000F0";
  constant REG_INT_TAB_EN          : std_logic_vector(19 downto 0) := x"00100";
  -- BAR1 registers: end


  --! Address Offset assignment
  --! --> BAR2 User Application Registers Addresses
  --! -- leave 16x8 = 128 bits space per register
  ------------------------------------
  ---- ## GENERATED code BEGIN #1 ----
  ------------------------------------

  --** Bar2

  --** GenericBoardInformation
  constant REG_REG_MAP_VERSION                : std_logic_vector(19 downto 0) := x"00000";
  constant REG_BOARD_ID_TIMESTAMP             : std_logic_vector(19 downto 0) := x"00010";
  constant REG_GIT_COMMIT_TIME                : std_logic_vector(19 downto 0) := x"00020";
  constant REG_GIT_TAG                        : std_logic_vector(19 downto 0) := x"00030";
  constant REG_GIT_COMMIT_NUMBER              : std_logic_vector(19 downto 0) := x"00040";
  constant REG_GIT_HASH                       : std_logic_vector(19 downto 0) := x"00050";
  constant REG_STATUS_LEDS                    : std_logic_vector(19 downto 0) := x"00060";
  constant REG_GENERIC_CONSTANTS              : std_logic_vector(19 downto 0) := x"00070";
  constant REG_CARD_TYPE                      : std_logic_vector(19 downto 0) := x"00080";
  constant REG_PCIE_ENDPOINT                  : std_logic_vector(19 downto 0) := x"00090";
  constant REG_NUMBER_OF_PCIE_ENDPOINTS       : std_logic_vector(19 downto 0) := x"000a0";

  --** HouseKeepingControlsAndMonitors
  constant REG_MMCM_MAIN_PLL_LOCK             : std_logic_vector(19 downto 0) := x"01300";
  constant REG_I2C_WR                         : std_logic_vector(19 downto 0) := x"01310";
  constant REG_I2C_RD                         : std_logic_vector(19 downto 0) := x"01320";
  constant REG_FPGA_CORE_TEMP                 : std_logic_vector(19 downto 0) := x"01330";
  constant REG_FPGA_CORE_VCCINT               : std_logic_vector(19 downto 0) := x"01340";
  constant REG_FPGA_CORE_VCCAUX               : std_logic_vector(19 downto 0) := x"01350";
  constant REG_FPGA_CORE_VCCBRAM              : std_logic_vector(19 downto 0) := x"01360";
  constant REG_FPGA_DNA                       : std_logic_vector(19 downto 0) := x"01370";
  constant REG_INT_TEST                       : std_logic_vector(19 downto 0) := x"01800";
  constant REG_DMA_BUSY_STATUS                : std_logic_vector(19 downto 0) := x"01810";

  --** Wishbone
  constant REG_WISHBONE_CONTROL               : std_logic_vector(19 downto 0) := x"02000";
  constant REG_WISHBONE_WRITE                 : std_logic_vector(19 downto 0) := x"02010";
  constant REG_WISHBONE_READ                  : std_logic_vector(19 downto 0) := x"02020";
  constant REG_WISHBONE_STATUS                : std_logic_vector(19 downto 0) := x"02030";

  --** Application
  constant REG_LOOPBACK                       : std_logic_vector(19 downto 0) := x"03000";
  -----------------------------------
  ---- GENERATED code END #1 ##  ----
  -----------------------------------

  --!
  --! --> CONTROL: Read/Write User Application Registers (Written by PCIe)
  ------------------------------------
  ---- ## GENERATED code BEGIN #2 ----
  ------------------------------------
  -- Bitfields of Control Record
  type bitfield_i2c_wr_t_type is record
    I2C_WREN                       : std_logic_vector(64 downto 64);  -- Any write to this register triggers an I2C read or write sequence
    DATA_BYTE3                     : std_logic_vector(34 downto 27);  -- Data byte 3 used when RW16BIT is set
    RW16BIT                        : std_logic_vector(26 downto 26);  -- Set to 1 to Write 3 bytes (ADDR + 16 data bits) or read 16 data bits.
    WRITE_2BYTES                   : std_logic_vector(24 downto 24);  -- Write two bytes
    DATA_BYTE2                     : std_logic_vector(23 downto 16);  -- Data byte 2
    DATA_BYTE1                     : std_logic_vector(15 downto 8);   -- Data byte 1
    SLAVE_ADDRESS                  : std_logic_vector(7 downto 1);    -- Slave address
    READ_NOT_WRITE                 : std_logic_vector(0 downto 0);    -- READ/<o>WRITE</o>
  end record;

  type bitfield_i2c_rd_t_type is record
    I2C_RDEN                       : std_logic_vector(64 downto 64);  -- Any write to this register pops the last I2C data from the FIFO
  end record;

  type bitfield_int_test_t_type is record
    TRIGGER                        : std_logic_vector(64 downto 64);  -- Fire a test MSIx interrupt set in IRQ
    IRQ                            : std_logic_vector(3 downto 0);    -- Set this field to a value equal to the MSIX interrupt to be fired. The write triggers the interrupt immediately.
  end record;

  type bitfield_dma_busy_status_t_type is record
    CLEAR_LATCH                    : std_logic_vector(64 downto 64);  -- Any write to this register clears TOHOST_BUSY_LATCHED
    ENABLE                         : std_logic_vector(4 downto 4);    -- Enable the DMA buffer on the server as a source of busy
  end record;

  type bitfield_wishbone_control_w_type is record
    WRITE_NOT_READ                 : std_logic_vector(32 downto 32);  -- wishbone write command wishbone read command
    ADDRESS                        : std_logic_vector(31 downto 0);   -- Slave address for Wishbone bus
  end record;

  type bitfield_wishbone_write_t_type is record
    WRITE_ENABLE                   : std_logic_vector(64 downto 64);  -- Any write to this register triggers a write to the Wupper to Wishbone fifo
    DATA                           : std_logic_vector(31 downto 0);   -- Wishbone
  end record;

  type bitfield_wishbone_read_t_type is record
    READ_ENABLE                    : std_logic_vector(64 downto 64);  -- Any write to this register triggers a read from the Wishbone to Wupper fifo
    TRIGGER                        : std_logic_vector(33 downto 33);  -- Dummy write bitfield to issue a trigger to READ_ENABLE
  end record;


  -- Control Record
  type register_map_control_type is record
    STATUS_LEDS                    : std_logic_vector(7 downto 0);    -- Board GPIO Leds
    I2C_WR                         : bitfield_i2c_wr_t_type;         -- House Keeping Controls and Monitors 
    I2C_RD                         : bitfield_i2c_rd_t_type;         -- House Keeping Controls and Monitors 
    INT_TEST                       : bitfield_int_test_t_type;       -- House Keeping Controls and Monitors 
    DMA_BUSY_STATUS                : bitfield_dma_busy_status_t_type;  -- House Keeping Controls and Monitors 
    WISHBONE_CONTROL               : bitfield_wishbone_control_w_type;  -- Wishbone 
    WISHBONE_WRITE                 : bitfield_wishbone_write_t_type;  -- Wishbone 
    WISHBONE_READ                  : bitfield_wishbone_read_t_type;  -- Wishbone 
    LOOPBACK                       : std_logic_vector(7 downto 0);    -- for every DMA descriptor
                                                                      -- 0: Generate data from a counter value
                                                                      -- 1: Loop back data from FromHost to ToHost DMA
                                                                      
  end record;
  -----------------------------------
  ---- GENERATED code END #2 ##  ----
  -----------------------------------

  constant REG_BUSY_THRESH_ASSERT_C : std_logic_vector(63 downto 0) := x"0000_0000_0C80_0000"; --200 MB busy threshold default value.
  constant REG_BUSY_THRESH_NEGATE_C : std_logic_vector(63 downto 0) := x"0000_0000_0DC0_0000"; --220 MB busy threshold default value.

  --!
  --! --> Read/Write User Application Registers DEFAULT values (Written by PCIe)
  ------------------------------------
  ---- ## GENERATED code BEGIN #3 ----
  ------------------------------------
  constant REG_STATUS_LEDS_C                       : std_logic_vector(7 downto 0)     := x"ab";                 -- Board GPIO Leds
  constant REG_I2C_WR_I2C_WREN_C                   : std_logic_vector(64 downto 64)   := "0";                   -- Any write to this register triggers an I2C read or write sequence
  constant REG_I2C_WR_DATA_BYTE3_C                 : std_logic_vector(34 downto 27)   := x"00";                 -- Data byte 3 used when RW16BIT is set
  constant REG_I2C_WR_RW16BIT_C                    : std_logic_vector(26 downto 26)   := "0";                   -- Set to 1 to Write 3 bytes (ADDR + 16 data bits) or read 16 data bits.
  constant REG_I2C_WR_WRITE_2BYTES_C               : std_logic_vector(24 downto 24)   := "0";                   -- Write two bytes
  constant REG_I2C_WR_DATA_BYTE2_C                 : std_logic_vector(23 downto 16)   := x"00";                 -- Data byte 2
  constant REG_I2C_WR_DATA_BYTE1_C                 : std_logic_vector(15 downto 8)    := x"00";                 -- Data byte 1
  constant REG_I2C_WR_SLAVE_ADDRESS_C              : std_logic_vector(7 downto 1)     := "0000000";             -- Slave address
  constant REG_I2C_WR_READ_NOT_WRITE_C             : std_logic_vector(0 downto 0)     := "0";                   -- READ/<o>WRITE</o>
  constant REG_I2C_RD_I2C_RDEN_C                   : std_logic_vector(64 downto 64)   := "0";                   -- Any write to this register pops the last I2C data from the FIFO
  constant REG_INT_TEST_TRIGGER_C                  : std_logic_vector(64 downto 64)   := "0";                   -- Fire a test MSIx interrupt set in IRQ
  constant REG_INT_TEST_IRQ_C                      : std_logic_vector(3 downto 0)     := x"0";                  -- Set this field to a value equal to the MSIX interrupt to be fired. The write triggers the interrupt immediately.
  constant REG_DMA_BUSY_STATUS_CLEAR_LATCH_C       : std_logic_vector(64 downto 64)   := "0";                   -- Any write to this register clears TOHOST_BUSY_LATCHED
  constant REG_DMA_BUSY_STATUS_ENABLE_C            : std_logic_vector(4 downto 4)     := "0";                   -- Enable the DMA buffer on the server as a source of busy
  constant REG_WISHBONE_CONTROL_WRITE_NOT_READ_C   : std_logic_vector(32 downto 32)   := "0";                   -- wishbone write command wishbone read command
  constant REG_WISHBONE_CONTROL_ADDRESS_C          : std_logic_vector(31 downto 0)    := x"00000000";           -- Slave address for Wishbone bus
  constant REG_WISHBONE_WRITE_WRITE_ENABLE_C       : std_logic_vector(64 downto 64)   := "0";                   -- Any write to this register triggers a write to the Wupper to Wishbone fifo
  constant REG_WISHBONE_WRITE_DATA_C               : std_logic_vector(31 downto 0)    := x"00000000";           -- Wishbone
  constant REG_WISHBONE_READ_READ_ENABLE_C         : std_logic_vector(64 downto 64)   := "0";                   -- Any write to this register triggers a read from the Wishbone to Wupper fifo
  constant REG_WISHBONE_READ_TRIGGER_C             : std_logic_vector(33 downto 33)   := "0";                   -- Dummy write bitfield to issue a trigger to READ_ENABLE
  constant REG_LOOPBACK_C                          : std_logic_vector(7 downto 0)     := x"00";                 -- for every DMA descriptor
                                                                                                                -- 0: Generate data from a counter value
                                                                                                                -- 1: Loop back data from FromHost to ToHost DMA
                                                                                                                
  -----------------------------------
  ---- GENERATED code END #3 ##  ----
  -----------------------------------

  --!
  --! --> MONITOR: Read Only User Application Registers (Read by PCIe)
  ------------------------------------
  ---- ## GENERATED code BEGIN #4 ----
  ------------------------------------

--
-- GenericBoardInformation
--
  type bitfield_generic_constants_r_type is record
    INTERRUPTS                     : std_logic_vector(15 downto 8);   -- Number of Interrupts
    DESCRIPTORS                    : std_logic_vector(7 downto 0);    -- Number of Descriptors
  end record;

  -- GenericBoardInformation
  type register_map_gen_board_info_type is record
    REG_MAP_VERSION                : std_logic_vector(15 downto 0);   -- Register Map Version, 2.0 formatted as 0x0200
    BOARD_ID_TIMESTAMP             : std_logic_vector(39 downto 0);   -- Board ID Date / Time in BCD format YYMMDDhhmm
    GIT_COMMIT_TIME                : std_logic_vector(39 downto 0);   -- Board ID GIT Commit time of current revision, Date / Time in BCD format YYMMDDhhmm
    GIT_TAG                        : std_logic_vector(63 downto 0);   -- String containing the current GIT TAG
    GIT_COMMIT_NUMBER              : std_logic_vector(31 downto 0);   -- Number of GIT commits after current GIT_TAG
    GIT_HASH                       : std_logic_vector(31 downto 0);   -- Short GIT hash (32 bit)
    GENERIC_CONSTANTS              : bitfield_generic_constants_r_type;
    CARD_TYPE                      : std_logic_vector(63 downto 0);   -- Card Type:
                                                                      --   - 105 (0x069): KCU-105
                                                                      --   - 128 (0x080): VCU128
                                                                      --   - 180 (0x0B4): VMK180
                                                                      --   - 709 (0x2c5): VC-709
                                                                      --   - 710 (0x2c6): HTG-710
                                                                      --   - 711 (0x2c7): BNL-711
                                                                      --   - 712 (0x2c8): BNL-712
                                                                      
    PCIE_ENDPOINT                  : std_logic_vector(0 downto 0);    -- Indicator of the PCIe endpoint on BNL71x cards with two endpoints. 0 or 1
    NUMBER_OF_PCIE_ENDPOINTS       : std_logic_vector(1 downto 0);    -- Number of PCIe endpoints on the card. The VCU128 cards have 2 endpoints
end record;
--
-- HouseKeepingControlsAndMonitors
--
  type bitfield_i2c_wr_r_type is record
    I2C_FULL                       : std_logic_vector(25 downto 25);  -- I2C FIFO full
  end record;
  type bitfield_i2c_rd_r_type is record
    I2C_EMPTY                      : std_logic_vector(8 downto 8);    -- I2C FIFO Empty
    I2C_DOUT                       : std_logic_vector(7 downto 0);    -- I2C READ Data
  end record;
  type bitfield_dma_busy_status_r_type is record
    TOHOST_BUSY_LATCHED            : std_logic_vector(3 downto 3);    -- A tohost descriptor has passed BUSY_THRESHOLD_ASSERT in the past, busy flag was set
    FROMHOST_BUSY_LATCHED          : std_logic_vector(2 downto 2);    -- A fromhost descriptor has passed BUSY_THRESHOLD_ASSERT in the past, busy flag was set
    FROMHOST_BUSY                  : std_logic_vector(1 downto 1);    -- A fromhost descriptor passed BUSY_THRESHOLD_ASSERT, busy flag set
    TOHOST_BUSY                    : std_logic_vector(0 downto 0);    -- A tohost descriptor passed BUSY_THRESHOLD_ASSERT, busy flag set
  end record;

  -- HouseKeepingControlsAndMonitors
  type register_map_hk_monitor_type is record
    MMCM_MAIN_PLL_LOCK             : std_logic_vector(0 downto 0);    -- Main MMCM PLL Lock Status
    I2C_WR                         : bitfield_i2c_wr_r_type;       
    I2C_RD                         : bitfield_i2c_rd_r_type;       
    FPGA_CORE_TEMP                 : std_logic_vector(11 downto 0);   -- XADC temperature monitor for the FPGA CORE
                                                                      -- for Virtex7
                                                                      -- temp (C)= ((FPGA_CORE_TEMP* 503.975)/4096)-273.15
                                                                      -- for Kintex Ultrascale
                                                                      -- temp (C)= ((FPGA_CORE_TEMP* 502.9098)/4096)-273.8195
                                                                      
    FPGA_CORE_VCCINT               : std_logic_vector(11 downto 0);   -- XADC voltage measurement VCCINT = (FPGA_CORE_VCCINT *3.0)/4096
    FPGA_CORE_VCCAUX               : std_logic_vector(11 downto 0);   -- XADC voltage measurement VCCAUX = (FPGA_CORE_VCCAUX *3.0)/4096
    FPGA_CORE_VCCBRAM              : std_logic_vector(11 downto 0);   -- XADC voltage measurement VCCBRAM = (FPGA_CORE_VCCBRAM *3.0)/4096
    FPGA_DNA                       : std_logic_vector(63 downto 0);   -- Unique identifier of the FPGA
    DMA_BUSY_STATUS                : bitfield_dma_busy_status_r_type;
end record;
--
-- Wishbone
--
  -- Bitfields of Wishbone
  type bitfield_wishbone_write_r_type is record
    FULL                           : std_logic_vector(32 downto 32);  -- Wishbone
  end record;
  type bitfield_wishbone_read_r_type is record
    EMPTY                          : std_logic_vector(32 downto 32);  -- Indicates that the Wishbone to Wupper fifo is empty
    DATA                           : std_logic_vector(31 downto 0);   -- Wishbone read data
  end record;
  type bitfield_wishbone_status_r_type is record
    INT                            : std_logic_vector(4 downto 4);    -- interrupt
    RETRY                          : std_logic_vector(3 downto 3);    -- Interface is not ready to accept data cycle should be retried
    STALL                          : std_logic_vector(2 downto 2);    -- When pipelined mode slave can't accept additional transactions in its queue
    ACKNOWLEDGE                    : std_logic_vector(1 downto 1);    -- Indicates the termination of a normal bus cycle
    ERROR                          : std_logic_vector(0 downto 0);    -- Address not mapped by the crossbar
  end record;

  -- Wishbone
  type wishbone_monitor_type is record
    WISHBONE_WRITE                 : bitfield_wishbone_write_r_type;
    WISHBONE_READ                  : bitfield_wishbone_read_r_type;
    WISHBONE_STATUS                : bitfield_wishbone_status_r_type;
end record;
  

  -- Monitor interface toward the dma_control block
  type register_map_monitor_type is record
    register_map_gen_board_info  : register_map_gen_board_info_type;
    register_map_hk_monitor  : register_map_hk_monitor_type;
    wishbone_monitor  : wishbone_monitor_type;
  end record;
  
  -- Constants for unused monitor records

  constant register_map_gen_board_info_c : register_map_gen_board_info_type := (
    REG_MAP_VERSION                => (others => '0'),
    BOARD_ID_TIMESTAMP             => (others => '0'),
    GIT_COMMIT_TIME                => (others => '0'),
    GIT_TAG                        => (others => '0'),
    GIT_COMMIT_NUMBER              => (others => '0'),
    GIT_HASH                       => (others => '0'),
    GENERIC_CONSTANTS              => (others => (others => '0')),
    CARD_TYPE                      => (others => '0'),
    PCIE_ENDPOINT                  => (others => '0'),
    NUMBER_OF_PCIE_ENDPOINTS       => (others => '0')
  );

  constant register_map_hk_monitor_c : register_map_hk_monitor_type := (
    MMCM_MAIN_PLL_LOCK             => (others => '0'),
    I2C_WR                         => (others => (others => '0')),
    I2C_RD                         => (others => (others => '0')),
    FPGA_CORE_TEMP                 => (others => '0'),
    FPGA_CORE_VCCINT               => (others => '0'),
    FPGA_CORE_VCCAUX               => (others => '0'),
    FPGA_CORE_VCCBRAM              => (others => '0'),
    FPGA_DNA                       => (others => '0'),
    DMA_BUSY_STATUS                => (others => (others => '0'))
  );

  constant wishbone_monitor_c : wishbone_monitor_type := (
    WISHBONE_WRITE                 => (others => (others => '0')),
    WISHBONE_READ                  => (others => (others => '0')),
    WISHBONE_STATUS                => (others => (others => '0'))
  );
  -----------------------------------
  ---- GENERATED code END #4 ##  ----
  -----------------------------------

    type DDR_out_type is record
        act_n   :  STD_LOGIC_VECTOR ( 0 to 0 );
        adr     :  STD_LOGIC_VECTOR ( 16 downto 0 );
        ba      :  STD_LOGIC_VECTOR ( 1 downto 0 );
        bg      :  STD_LOGIC_VECTOR ( 1 downto 0 );
        ck_c    :  STD_LOGIC_VECTOR ( 1 downto 0 );
        ck_t    :  STD_LOGIC_VECTOR ( 1 downto 0 );
        cke     :  STD_LOGIC_VECTOR ( 1 downto 0 );
        cs_n    :  STD_LOGIC_VECTOR ( 1 downto 0 );
        odt     :  STD_LOGIC_VECTOR ( 1 downto 0 );
        reset_n :  STD_LOGIC_VECTOR ( 0 to 0 );
    end record;
    type DDR_out_array_type is array(natural range <>) of DDR_out_type;
    type DDR_inout_type is record
        dm_n  : STD_LOGIC_VECTOR ( 8 downto 0 );
        dq    : STD_LOGIC_VECTOR ( 71 downto 0 );
        dqs_c : STD_LOGIC_VECTOR ( 8 downto 0 );
        dqs_t : STD_LOGIC_VECTOR ( 8 downto 0 );
    end record;
    type DDR_inout_array_type is array(natural range <>) of DDR_inout_type;
    type DDR_in_type is record
        sys_clk_n : STD_LOGIC_VECTOR ( 0 to 0 );
        sys_clk_p : STD_LOGIC_VECTOR ( 0 to 0 );
    end record;
    type DDR_in_array_type is array(natural range <>) of DDR_in_type;

    type LPDDR_out_type is record
        ca_a    : STD_LOGIC_VECTOR ( 5 downto 0 );
        ca_b    : STD_LOGIC_VECTOR ( 5 downto 0 );
        ck_c_a  : STD_LOGIC_VECTOR ( 0 to 0 );
        ck_c_b  : STD_LOGIC_VECTOR ( 0 to 0 );
        ck_t_a  : STD_LOGIC_VECTOR ( 0 to 0 );
        ck_t_b  : STD_LOGIC_VECTOR ( 0 to 0 );
        cke_a   : STD_LOGIC_VECTOR ( 0 to 0 );
        cke_b   : STD_LOGIC_VECTOR ( 0 to 0 );
        cs_a    : STD_LOGIC_VECTOR ( 0 to 0 );
        cs_b    : STD_LOGIC_VECTOR ( 0 to 0 );
        reset_n : STD_LOGIC_VECTOR ( 0 to 0 );
    end record;
    type LPDDR_out_array_type is array(natural range <>) of LPDDR_out_type;
    type LPDDR_inout_type is record
        dmi_a   : STD_LOGIC_VECTOR ( 1 downto 0 );
        dmi_b   : STD_LOGIC_VECTOR ( 1 downto 0 );
        dq_a    : STD_LOGIC_VECTOR ( 15 downto 0 );
        dq_b    : STD_LOGIC_VECTOR ( 15 downto 0 );
        dqs_c_a : STD_LOGIC_VECTOR ( 1 downto 0 );
        dqs_c_b : STD_LOGIC_VECTOR ( 1 downto 0 );
        dqs_t_a : STD_LOGIC_VECTOR ( 1 downto 0 );
        dqs_t_b : STD_LOGIC_VECTOR ( 1 downto 0 );
    end record;
    type LPDDR_inout_array_type is array(natural range <>) of LPDDR_inout_type;
    type LPDDR_in_type is record
        sys_clk_n : STD_LOGIC_VECTOR ( 0 to 0 );
        sys_clk_p : STD_LOGIC_VECTOR ( 0 to 0 );
    end record;
    type LPDDR_in_array_type is array(natural range <>) of LPDDR_in_type;

    function NUM_DDR(CARD_TYPE: integer) return integer;
    function NUM_LPDDR(CARD_TYPE: integer) return integer;
    function NUM_LEDS(CARD_TYPE: integer) return integer;



end package pcie_package ;

package body pcie_package is
    function to_sl( A: std_logic_vector) return std_logic is
    begin
        return A(A'low);
    end function to_sl;
    
    function or_reduce(slv : in std_logic_vector) return std_logic is
      variable res_v : std_logic := '0';  -- Null slv vector will also return '0'
    begin
      for i in slv'range loop
        res_v := res_v or slv(i);
      end loop;
      return res_v;
    end function;
    
     --! If we have multiple descriptors ToHost (take one off for FromHost direction) we have more FIFOs, let's make them less deep.
    function TOHOSTFIFO_DEPTH(NUMBER_OF_DESCRIPTORS : integer; FIRMWARE_MODE: integer) return integer is
    begin
        --! Deeper FIFOs for FULL or INTERLAKEN
        if FIRMWARE_MODE = 1 or FIRMWARE_MODE = 10 then
            case NUMBER_OF_DESCRIPTORS is
                when 2 => return 4096;
                when 3 => return 4096;
                when 4 => return 4096;
                when 5 => return 2048;
                when 6 => return 2048;
                when 7 => return 2048;
                when 8 => return 2048;
                when others => return 4096;
            end case;
        else
            case NUMBER_OF_DESCRIPTORS is
                when 2 => return 4096;
                when 3 => return 2048;
                when 4 => return 2048;
                when 5 => return 1024;
                when 6 => return 1024;
                when 7 => return 1024;
                when 8 => return 1024;
                when others => return 4096;
            end case;
        end if;
    end function;

    function f_log2 (constant x : positive) return natural is
        variable i : natural;
    begin
        i := 0;
        while (2**i < x) and i < 31 loop
            i := i + 1;
        end loop;
        return i;
    end function;
    
    function NUM_DDR(CARD_TYPE: integer) return integer is
    begin
        if CARD_TYPE = 182 or CARD_TYPE = 155 then --For now only implement DDR controller for FLX182 and FLX155. FLX181 has 3 but we don't use them for now.
            return 1;
        else
            return 0;
        end if;
    end function;

    function NUM_LPDDR(CARD_TYPE: integer) return integer is
    begin
        if CARD_TYPE = 120 then
            return 4;
        else
            return 0;
        end if;
    end function;

    function NUM_LEDS(CARD_TYPE: integer) return integer is
    begin
        if CARD_TYPE = 709 or CARD_TYPE = 710 then
            return 8;
        elsif CARD_TYPE = 711 or CARD_TYPE = 712 then
            return 7;
        elsif CARD_TYPE = 800 or CARD_TYPE = 181 or CARD_TYPE = 182 or CARD_TYPE = 155 or CARD_TYPE = 120 then
            return 4;
        else
            return 8;
        end if;
    end function;

end pcie_package;
